<script setup lang="ts">
import type Node from "element-plus/es/components/tree/src/model/node";
import {
  Delete,
  Download,
  Edit,
  Grid,
  Plus,
  RefreshLeft,
  Search,
  Check
} from "@element-plus/icons-vue";
import {
  ElForm,
  ElNotification,
  ElTable,
  ElTree,
  ElMessage,
  ElMessageBox
} from "element-plus";
import { reactive, ref, onMounted, nextTick } from "vue";
import {
  getCurrentLevel,
  getRoleListByPage,
  MenuItem,
  ResultRole,
  getMenuListLazy,
  getMenuSubById,
  updateRoleMenu,
  getRoleById,
  getDeptList,
  addRole,
  DelRole,
  getDeptSuperior,
  editRole,
  exportRoleList
} from "@/api/system";
import { cloneDeep } from "@pureadmin/utils";
import { downloadFile } from "@/utils";
const queryShow = ref(true);
const queryForm = reactive({
  data: {
    blurry: undefined,
    createTime: []
  }
});
const resetQuery = () => {
  queryForm.data = {
    blurry: undefined,
    createTime: []
  };
};
const currentLevel = ref(3);
const init = async () => {
  const { level } = await getCurrentLevel();
  currentLevel.value = level;
};
init();
const tableData = reactive({
  data: []
});
const colums = reactive({
  data: [
    {
      label: "名称",
      prop: "name"
    },
    {
      label: "数据权限",
      prop: "dataScope"
    },
    {
      label: "角色级别",
      prop: "level"
    },
    {
      label: "描述",
      prop: "description"
    },
    {
      label: "创建日期",
      prop: "createTime",
      width: "200px"
    }
  ]
});
const defaultColums = reactive({
  data: [
    {
      label: "名称",
      prop: "name"
    },
    {
      label: "数据权限",
      prop: "dataScope"
    },
    {
      label: "角色级别",
      prop: "level"
    },
    {
      label: "描述",
      prop: "description"
    },
    {
      label: "创建日期",
      prop: "createTime",
      width: "200px"
    }
  ]
});
const pageObj = reactive({
  data: {
    currentPage: 1,
    pageSize: 10,
    total: 0
  }
});
const loading = ref(false);
const multipleTableRef = ref<InstanceType<typeof ElTable>>();
const multipleSelection = ref([]);
const checkAll = ref(true);
const isIndeterminate = ref(false);
const checkedCities = ref([]);

const handleCheckAllChange = (val: boolean) => {
  checkedCities.value = val ? defaultColums.data.map(item => item.prop) : [];
  isIndeterminate.value = false;
  if (checkedCities.value.length) {
    colums.data = defaultColums.data;
  } else {
    colums.data = [];
  }
};
const handleCheckedCitiesChange = (value: string[]) => {
  const checkedCount = value.length;
  checkAll.value = checkedCount === defaultColums.data.length;
  isIndeterminate.value =
    checkedCount > 0 && checkedCount < defaultColums.data.length;
  let cols = [];
  defaultColums.data.forEach(i => {
    if (value.indexOf(i.prop) > -1) {
      cols.push(i);
    }
  });
  colums.data = cols;
};
const getUser = () => {
  loading.value = true;
  return new Promise<ResultRole>(async (resolve, reject) => {
    let data = await getRoleListByPage({
      current: pageObj.data.currentPage,
      size: pageObj.data.pageSize,
      sort: "level,asc",
      blurry: queryForm.data.blurry ? queryForm.data.blurry : undefined,
      createTime: queryForm.data.createTime.length
        ? queryForm.data.createTime
        : undefined
    });
    loading.value = false;
    resolve(data);
  });
};
const handleSizeChange = () => {
  search();
};
const handleCurrentChange = async () => {
  getList();
};
const search = async () => {
  pageObj.data.currentPage = 1;
  let { content, totalElements } = await getUser();
  pageObj.data.total = totalElements;
  tableData.data = content;
};
const getList = async () => {
  let { content, totalElements } = await getUser();
  pageObj.data.total = totalElements;
  tableData.data = content;
};

onMounted(() => {
  search();
  checkedCities.value = colums.data.map(item => item.prop);
});

const props = {
  label: "label",
  children: "children",
  isLeaf: "leaf"
};
const loadNode = async (node: Node, resolve: (data: MenuItem[]) => void) => {
  let pid = 0;
  if (node && node.data && node.data.id) {
    pid = node.data.id;
  }
  let data = await getMenuListLazy({ pid: pid });
  return resolve(data);
};
const menuIds = ref([]);
const menuTree = ref<InstanceType<typeof ElTree>>();
const currentRowId = ref("");
const currentRow = ref(null);
const showButton = ref(false);
const rowClick = row => {
  menuTree.value.setCheckedKeys([]);
  currentRowId.value = row.id;
  currentRow.value = row;
  menuIds.value = [];
  row.menus.forEach(function (data) {
    menuIds.value.push(data.id);
  });
  showButton.value = true;
};
const menuLoading = ref(false);
const checkGetChild = async menu => {
  // 获取该节点的所有子节点，id 包含自身
  let childIds = await getMenuSubById({ id: menu.id });
  // 判断是否在 menuIds 中，如果存在则删除，否则添加
  if (menuIds.value.indexOf(menu.id) !== -1) {
    for (let i = 0; i < childIds.length; i++) {
      const index = menuIds.value.indexOf(childIds[i]);
      if (index !== -1) {
        menuIds.value.splice(index, 1);
      }
    }
  } else {
    for (let i = 0; i < childIds.length; i++) {
      const index = menuIds.value.indexOf(childIds[i]);
      if (index === -1) {
        menuIds.value.push(childIds[i]);
      }
    }
  }
  menuTree.value.setCheckedKeys(menuIds.value);
};

const updateRow = () => {
  getRoleById(currentRowId.value).then(res => {
    for (let i = 0; i < tableData.data.length; i++) {
      if (res.id === tableData.data[i].id) {
        tableData.data[i] = res;
        break;
      }
    }
  });
};
const saveMenu = () => {
  menuLoading.value = true;
  const role = { id: currentRowId.value, menus: [] };
  // 得到已选中的 key 值
  menuIds.value.forEach(function (id) {
    const menu = { id: id };
    role.menus.push(menu);
  });
  updateRoleMenu(role)
    .then(() => {
      ElNotification({
        title: "系统提示",
        message: "保存成功",
        type: "success"
      });
      menuLoading.value = false;
      updateRow();
    })
    .catch(err => {
      menuLoading.value = false;
      console.log(err.response.data.message);
    });
};
const depts = ref([]);
const deptDatas = ref([]);
const getDepts = () => {
  getDeptList({ enabled: true }).then(res => {
    depts.value = res.content.map(function (obj) {
      if (obj.hasChildren) {
        obj.children = null;
      }
      return obj;
    });
  });
};
const propsDept = {
  label: "label",
  hasChildren: "hasChildren",
  children: "children",
  isLeaf: "leaf"
};
const getDeptData = (pid: number | undefined, name: string | undefined) => {
  return new Promise(async (resolve, reject) => {
    let { content } = await getDeptList({
      sort: "id,desc",
      pid: pid ?? undefined,
      name: name ?? undefined
    });
    resolve(content);
  });
};
const loadNodeDept = async (node: Node, resolve: any) => {
  if (status.value === "edit" && !node.data.id) {
    resolve([]);
  } else {
    let data = await getDeptData(node?.data?.id, undefined);
    return resolve(data);
  }
};
const changeScope = () => {
  if (form.data.dataScope === "自定义") {
    // getDepts()
  }
};
const ruleForm = ref<InstanceType<typeof ElForm>>();
const form = reactive({
  data: {
    name: undefined,
    level: 3,
    dataScope: undefined,
    menus: null,
    description: undefined,
    depts: []
  },
  rules: {
    name: [{ required: true, message: "请输入名称", trigger: "blur" }],
    permission: [{ required: true, message: "请输入权限", trigger: "blur" }]
  }
});
const resetForm = () => {
  ruleForm.value.resetFields();
};
const addDialog = ref(false);
const title = ref("新增用户");
const status = ref("add");
const addUser = () => {
  addDialog.value = true;
  title.value = "新增角色";
  status.value = "add";
  deptDatas.value = [];
  form.data = {
    name: undefined,
    level: 3,
    dataScope: undefined,
    menus: null,
    description: undefined,
    depts: []
  };
  resetForm();
};
const beforeClose = d => {
  form.data = {
    name: undefined,
    level: 3,
    dataScope: undefined,
    menus: null,
    description: undefined,
    depts: []
  };
  deptDatas.value = [];
  nextTick(() => {
    d();
  });
};
const cancel = () => {
  form.data = {
    name: undefined,
    level: 3,
    dataScope: undefined,
    menus: null,
    description: undefined,
    depts: []
  };
  ruleForm.value.resetFields();
  nextTick(() => {
    addDialog.value = false;
  });
};
const submit = async () => {
  if (form.data.dataScope === "自定义" && deptDatas.value.length === 0) {
    ElMessage({
      message: "自定义数据权限不能为空",
      type: "warning"
    });
    return false;
  } else if (form.data.dataScope === "自定义") {
    const depts = [];
    deptDatas.value.forEach(function (data) {
      const dept = { id: data };
      depts.push(dept);
    });
    form.data.depts = depts;
  } else {
    form.data.depts = [];
  }
  ruleForm.value.validate(async valid => {
    if (valid) {
      let data = cloneDeep(form.data);
      if (status.value === "add") {
        await addRole(data);
        ElNotification({
          title: "系统提示",
          message: "角色创建成功",
          type: "success"
        });
      } else {
        await editRole(data);
        ElNotification({
          title: "系统提示",
          message: "编辑成功",
          type: "success"
        });
      }
      resetForm();
      nextTick(() => {
        addDialog.value = false;
        search();
      });
    }
  });
};
const handleSelectionChange = val => {
  multipleSelection.value = val;
};
const selectableFunc = (row, index) => {
  if (currentLevel.value === 999) {
    return true;
  } else {
    return row.level < currentLevel.value;
  }
};
const delConfirm = async row => {
  await DelRole([row.id]);
  ElNotification({
    title: "系统提示",
    message: "删除成功",
    type: "success"
  });
  search();
};
const delSelect = () => {
  if (multipleSelection.value.length) {
    ElMessageBox.confirm(
      `确认删除选中的${multipleSelection.value.length}条数据?`,
      "系统提示",
      {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
        dangerouslyUseHTMLString: true,
        draggable: true
      }
    ).then(async () => {
      await DelRole(multipleSelection.value.map(i => i.id));
      ElNotification({
        title: "系统提示",
        message: "删除成功",
        type: "success"
      });
      search();
    });
  }
};
const getSupDepts = mdepts => {
  const ids = [];
  mdepts.forEach(dept => {
    ids.push(dept.id);
  });
  getDeptSuperior(ids).then(res => {
    const date = res.content;
    buildDepts(date);
    depts.value = date;
  });
};
const buildDepts = depts => {
  depts.forEach(data => {
    if (data.children) {
      buildDepts(data.children);
    }
    if (data.hasChildren && !data.children) {
      data.children = null;
    }
  });
};
const editRow = async row => {
  let data = cloneDeep(row);
  deptDatas.value = [];
  if (data.dataScope === "自定义") {
    getSupDepts(data.depts);
  }
  data.depts.forEach(function (dept) {
    deptDatas.value.push(dept.id);
  });
  // 将角色的菜单清空，避免日志入库数据过长
  data.menus = null;
  form.data = data;
  addDialog.value = true;
  title.value = "编辑角色";
  status.value = "edit";
};
const editSelect = () => {
  if (multipleSelection.value.length === 1) {
    editRow(multipleSelection.value[0]);
  }
};
const exportData = async () => {
  let res = await exportRoleList({
    current: pageObj.data.currentPage,
    size: pageObj.data.pageSize,
    sort: "level,asc",
    blurry: queryForm.data.blurry ? queryForm.data.blurry : undefined,
    createTime: queryForm.data.createTime.length
      ? queryForm.data.createTime
      : undefined
  });
  downloadFile(res, "角色数据", "xlsx");
};
</script>

<template>
  <div class="main h-[calc(100%-29px)]">
    <div class="w-full">
      <div v-if="queryShow" class="mb-[10px] w-full search-form">
        <el-form :inline="true" :model="queryForm.data" label-width="0px">
          <el-form-item>
            <el-input
              v-model="queryForm.data.blurry"
              clearable
              placeholder="输入名称或描述搜索"
            />
          </el-form-item>
          <el-form-item>
            <el-date-picker
              v-model="queryForm.data.createTime"
              type="datetimerange"
              range-separator=":"
              start-placeholder="开始日期"
              end-placeholder="结束日期"
              value-format="YYYY-MM-DD HH:mm:ss"
            />
          </el-form-item>
          <el-form-item class="ml-[10px]">
            <el-button type="primary" :icon="Search" @click="search"
              >搜索</el-button
            >
            <el-button :icon="RefreshLeft" @click="resetQuery">重置</el-button>
          </el-form-item>
        </el-form>
      </div>
      <div class="w-full">
        <div class="w-full flex justify-between">
          <div class="buttons flex align-center">
            <el-button type="primary" :icon="Plus" @click="addUser"
              >新增</el-button
            >
            <el-button
              type="success"
              :icon="Edit"
              :disabled="!(multipleSelection.length === 1)"
              @click="editSelect"
              >修改</el-button
            >
            <el-button
              type="danger"
              :icon="Delete"
              :disabled="!multipleSelection.length"
              @click="delSelect"
              >删除</el-button
            >
            <el-button type="warning" :icon="Download" @click="exportData"
              >导出</el-button
            >
          </div>
          <div class="settings">
            <el-button-group class="ml-4">
              <el-button
                type="primary"
                :icon="Search"
                @click="queryShow = !queryShow"
              />
              <el-button type="primary" :icon="RefreshLeft" @click="getList" />
              <el-popover placement="bottom" :width="200" trigger="click">
                <template #reference>
                  <el-button type="primary" :icon="Grid" />
                </template>
                <el-checkbox
                  v-model="checkAll"
                  :indeterminate="isIndeterminate"
                  @change="handleCheckAllChange"
                  >全选</el-checkbox
                >
                <el-checkbox-group
                  v-model="checkedCities"
                  class="columns-show-group"
                  @change="handleCheckedCitiesChange"
                >
                  <el-checkbox
                    v-for="item in defaultColums.data"
                    :key="item.prop"
                    :label="item.prop"
                    >{{ item.label }}</el-checkbox
                  >
                </el-checkbox-group>
              </el-popover>
            </el-button-group>
          </div>
        </div>
        <div class="flex justify-between">
          <div class="role w-[890px]">
            <div v-loading="loading" class="w-full mt-[10px]">
              <el-table
                ref="multipleTableRef"
                :data="tableData.data"
                style="width: 100%"
                @selection-change="handleSelectionChange"
                @row-click="rowClick"
              >
                <el-table-column
                  :selectable="selectableFunc"
                  type="selection"
                  width="55"
                />
                <el-table-column
                  v-for="item in colums.data"
                  :key="item.prop"
                  :prop="item.prop"
                  :label="item.label"
                  :width="item.width"
                />
                <el-table-column fixed="right" label="操作" width="120">
                  <template #default="scope">
                    <el-button
                      type="primary"
                      size="small"
                      :icon="Edit"
                      @click="editRow(scope.row)"
                    />
                    <el-popconfirm
                      width="200px"
                      title="确定删除本条数据吗？"
                      @confirm="delConfirm(scope.row)"
                    >
                      <template #reference>
                        <el-button type="danger" size="small" :icon="Delete" />
                      </template>
                    </el-popconfirm>
                  </template>
                </el-table-column>
              </el-table>
            </div>
            <div class="page w-full mt-[10px]">
              <el-pagination
                v-model:current-page="pageObj.data.currentPage"
                v-model:page-size="pageObj.data.pageSize"
                :page-sizes="[10, 20, 30, 40, 50, 100]"
                layout="total, sizes, prev, pager, next, jumper"
                :total="pageObj.data.total"
                @size-change="handleSizeChange"
                @current-change="handleCurrentChange"
              />
            </div>
          </div>
          <div class="menu w-[calc(100%-900px)] mt-[10px]">
            <el-card class="box-card" :shadow="false">
              <template #header>
                <div class="card-header flex justify-between">
                  <div>
                    <span>菜单分配</span>
                    <span v-if="currentRowId" class="text-[12px]">
                      当前选中的角色为({{ currentRow.name }})
                    </span>
                  </div>
                  <el-button
                    v-permission="['admin', 'roles:edit']"
                    :loading="menuLoading"
                    :disabled="!showButton"
                    size="small"
                    class="button"
                    type="primary"
                    :icon="Check"
                    @click="saveMenu"
                    >保存</el-button
                  >
                </div>
              </template>
              <div>
                <el-tree
                  ref="menuTree"
                  accordion
                  node-key="id"
                  :props="props"
                  :load="loadNode"
                  lazy
                  check-strictly
                  show-checkbox
                  :default-checked-keys="menuIds"
                  @check="checkGetChild"
                />
              </div>
            </el-card>
          </div>
        </div>
      </div>
    </div>
    <el-dialog
      v-model="addDialog"
      :close-on-click-modal="false"
      :before-close="beforeClose"
      :title="title"
      width="40%"
    >
      <el-form
        ref="ruleForm"
        label-width="80px"
        :model="form.data"
        :rules="form.rules"
      >
        <el-row :gutter="20">
          <el-col :span="24">
            <el-form-item label="角色名称" prop="name">
              <el-input v-model="form.data.name" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="角色级别" prop="level">
              <el-input-number
                v-model.number="form.data.level"
                :min="1"
                controls-position="right"
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="数据范围" prop="dataScope">
              <el-select
                v-model="form.data.dataScope"
                placeholder="请选择数据范围"
                @change="changeScope"
              >
                <el-option
                  v-for="item in ['全部', '本级', '自定义']"
                  :key="item"
                  :label="item"
                  :value="item"
                />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col v-if="form.data.dataScope === '自定义'" :span="24">
            <el-form-item label="数据权限" prop="depts">
              <!--              <treeselect-->
              <!--                v-model="deptDatas"-->
              <!--                :load-options="loadDepts"-->
              <!--                :options="depts"-->
              <!--                :flat="true"-->
              <!--                :auto-select-descendants="true"-->
              <!--                :default-expand-level="1"-->
              <!--                multiple-->
              <!--                style="width: 380px"-->
              <!--                placeholder="请选择"-->
              <!--              />-->
              <el-tree-select
                v-model="deptDatas"
                check-strictly
                multiple
                :render-after-expand="false"
                show-checkbox
                :expand-on-click-node="false"
                :data="depts"
                nodeKey="id"
                lazy
                :load="loadNodeDept"
                :props="propsDept"
              />
            </el-form-item>
          </el-col>
          <el-col :span="24">
            <el-form-item label="描述信息" prop="description">
              <el-input v-model="form.data.description" type="textarea" />
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>

      <template #footer>
        <span class="dialog-footer">
          <el-button @click="cancel">取消</el-button>
          <el-button type="primary" @click="submit"> 确认 </el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<style scoped lang="scss">
:deep(.el-dropdown-menu__item i) {
  margin: 0;
}

.main-content {
  //margin: 24px 24px 0 !important;
}

.search-form {
  :deep(.el-form-item) {
    margin-bottom: 12px;
  }
}
</style>
